class Damage {
  constructor(attr, timeLine, liuPaiSkills, enemy, calc) {
    this.Attr = attr
    this.TimeLine = timeLine
    this.LiuPaiSkills = liuPaiSkills
    this.calc = calc
    this.enemy = enemy
  }

  // 伤害判定流程
  // 总的伤害判定 = 原始伤害 * (会意/会心加成) *  增伤 * 穿透 * 减伤 * 定音 * 伤害加深
  /*****/
  // 原始伤害（每个类别单独算 外功 固伤 鸣金 破竹 牵丝 裂石） = (外功攻击 - 外功防御) * 技能倍率
  // 本系的 (本系元素攻击 + 大世界等级 + 武学技能 + 1) * 元素攻击倍数
  /*****/
  // 会心/会意/擦伤  擦伤的话只能计算 原始伤害 * 穿透
  // 先会判断是否精准命中 然后优先判定会意(最大外功) 再判断会心(最大~最小随机)
  // 没有精准命中 则判断是否会意 否则就是擦伤(最小外功)
  /*****/
  // 伤害整体计算流程  外功攻击： 外功攻击(按照上面的来) - 外功防御 + 外系元素攻击(例如牵丝流派 不算牵丝攻击)
  // 技能倍率 详细要看表
  /*****/
  // 增伤一般是 心法  + 技能
  /*****/
  // 穿透算法 穿透-抗性 如果是负数则 100 + (穿透-抗性) 为倍率  如果为正数则 100 + (穿透-抗性)/2 为倍率
  /*****/
  // 减伤看boss
  /****/
  // 定音看 武器 技能
  /****/
  // 增伤一般是 首领天赋树

  // 世界等级
  world_level = 12
  // 武学等级
  skill_level = 85

  calculate() {
    const damageList = []
    // 根据时间轴来计算伤害
    skillList.array.forEach(TimeLineSkill => {
      damageObj = {
        lastDamage: 0,
        ch: TimeLineSkill.ch,
        num: TimeLineSkill.num,
        spec: TimeLineSkill.specCh,
        qiJie: TimeLineSkill.isQiJie ? '是': '否'
      }
      damageObj.lastDamage = this.calculateOneSkill(TimeLineSkill)
      damageList.push(damageObj)
    });
    return damageList
  }

  calculateOneSkill(TimeLineSkill) {
    const skill = this.findSkill(TimeLineSkill)
    // 获取会心 会意 擦伤 普攻的概率
    const rate = this.calculateRate()

    // 需要去计算外功 鸣金 破竹 牵丝 裂石 的结果
    let skillDamage = this.caculateBaseDamage(skill, rate)

    // 加完之后在 乘以 增伤
    // 增伤包括 通用增伤 气竭增伤 武器增伤 技能增伤 特殊增伤（连中 风墙 这个要放到技能的特殊增伤里面）
    // 通用增伤
    skillDamage = this.calc.mul(skillDamage, this.calc.add(1, this.Attr.TongYong.add))
    // 气竭增伤
    if (TimeLineSkill.isQiJie) {
      skillDamage = this.calc.mul(skillDamage, this.calc.add(1, this.Attr.TongYong.qiJie))
    }
    // 武器增伤 这里先获取技能武器类型
    const wuQiAdd = this.Attr.wuQiAdd
    for (let type in wuQiAdd) {
      if (type == 'all' && wuQiAdd[type] > 0) {
        skillDamage = this.calc.mul(skillDamage, this.calc.add(1, wuQiAdd[type]))
      } else(type == TimeLineSkill.wuqi && wuQiAdd[type] > 0) {
        skillDamage = this.calc.mul(skillDamage, this.calc.add(1, wuQiAdd[type]))
      }
    }
    // 技能增伤 这里的匹配规则
    // 例如 shan-~ 会匹配扇的 ~ 和 ~-spec
    // san-xv 会匹配 伞的 xv-left
    const skillAdd = this.Attr.wuQiAdd
    for(let skl in skillAdd) {
      const skls = skl.split('-')
      // 匹配武器
      if(skls[0] == TimeLineSkill.wuqi) {
        //匹配技能 蓄力技
        if(skls[1] == 'xv' && TimeLineSkill.name.startsWith('xv-')) {
          skillDamage = this.calc.mul(skillDamage, this.calc.add(1, skillAdd[skl]))
        } else if(TimeLineSkill.name == skls[1] || TimeLineSkill.name == (skls[1] + '-spec')){
          // 匹配技能 其他
          skillDamage = this.calc.mul(skillDamage, this.calc.add(1, skillAdd[skl]))
        }
      }
    }

    // 特殊增伤 例如 连中20% 风墙20% 双风墙40%
    if(TimeLineSkill.specAdd > 0) {
      skillDamage = this.calc.mul(skillDamage, this.calc.add(1, TimeLineSkill.specAdd))
    }

    // 乘以技能次数 就是这个技能的期望伤害
    lastDamage = skillDamage * TimeLineSkill.num

    return {
      lastDamage,
      skill
    }
  }

  // 寻找这个skill
  findSkill(TimeLineSkill) {
    // 获取武器对应的所有技能
    const skills = this.liuPaiSkills[TimeLineSkill.wuqi]
    // 直接对应技能
    const name = TimeLineSkill.name
    let skill = ''
    for (let key in skills) {
      if (key != 'name' && key == name) {
        skill = skills[key]
      }
    }
    return skill
  }

  // 计算 外功 固伤 鸣金 破竹 牵丝 裂石
  caculateBaseDamage(skill, rate) {
    // 获取当前流派是什么流派
    const liuPaiName = this.liuPaiSkills.name
    // 需要传递的值max min chuanTou add

    // 外功伤害
    const waiGong = this.caculSkillShuXinDamage(this.Attr.WaiGong, skill, rate)
    // 固定伤害
    const guShangAttr = {
      max: skill.fixed,
      min: skill.fixed,
      chuanTou: this.Attr.WaiGong.chuanTou,
      add: this.Attr.WaiGong.add,
    }
    const guShang = this.caculSkillShuXinDamage(guShangAttr, skill, rate)
    // 鸣金
    let main = false
    if (liuPaiName.toUpperCase() == 'MINGJIN') {
      main = true
    }
    const mingJin = this.caculSkillShuXinDamage(this.Attr.MingJin, skill, rate, main)
    // 破竹
    main = false
    if (liuPaiName.toUpperCase() == 'POZHU') {
      main = true
    }
    const poZhu = this.caculSkillShuXinDamage(this.Attr.PoZhu, skill, rate, main)
    // 牵丝
    main = false
    if (liuPaiName.toUpperCase() == 'QIANSI') {
      main = true
    }
    const qianSi = this.caculSkillShuXinDamage(this.Attr.QianSi, skill, rate, main)
    // 裂石
    main = false
    if (liuPaiName.toUpperCase() == 'LIESHI') {
      main = true
    }
    const lieShi = this.caculSkillShuXinDamage(this.Attr.LieShi, skill, rate, main)
    // 所有伤害加起来就是这个技能单次的期望伤害
    const add_1 = this.calc.add(waiGong.last, guShang.last)
    const add_2 = this.calc.add(mingJin.last, poZhu.last)
    const add_3 = this.calc.add(qianSi.last, lieShi.last)
    const skillDamage = this.calc.add(this.calc.add(add_1, add_2), add_3)
    return skillDamage
  }

  // 计算每种可能性的占比
  calculateRate() {
    const tongYong = this.attr.TongYong
    const huiXin = tongYong.huiXin + tongYong.ZhiJieHuiXin
    const huiYi = tongYong.huiYi + tongYong.zhiJieHuiYi
    const jingZhunLv = tongYong.jingZhunLv

    // 计算概率
    // 未触发精准概率
    const no_jz = this.calc.desc(1, jingZhunLv)
    // 擦伤率期望
    const cashangLast = this.calc.mul(no_jz, this.calc.desc(1, huiYi))
    // 会心期望
    let huiXinLast = 0
    // 会意期望
    const huiYiLast = huiYi
    // 普攻期望
    let normalLast = 0
    if (this.calc.add(huiXin, huiYi) > 1) {
      // 如果会心+会意大于100% 则会心率 = 1 - 擦伤率 - 会意率
      huiXinLast = this.calc.desc(this.calc.desc(1, cashangLast), huiYiLast)
    } else {
      // 如果会心 + 会意小于100% 则 会心率 = 会心率 * 精准率 普攻几率 = 1 - 会心率 - 会意率 - 擦伤率
      huiXinLast = this.calc.mul(jingZhunLv, huiXin)
      const normalLast_1 = this.calc.desc(1, huiXinLast)
      const normalLast_2 = this.calc.desc(normalLast_1, huiYi)
      normalLast = this.calc.desc(normalLast_2, cashangLast)
      normalLast = normalLast < 0 ? 0 : normalLast
    }

    return {
      caShang: cashangLast,
      huiYi: huiYiLast,
      huiXin: huiXinLast,
      normal: normalLast,
    }
  }

  // 计算每种属性的期望伤害
  // 属性 技能 次数 伤害占比 是否为主属性
  caculSkillShuXinDamage(damageAttr, skill, rate, main = false) {
    // 计算当前外功期望值
    let avg = this.calc.div(this.calc.add(damageAttr.max, damageAttr.min), 2)
    if (damageAttr.max < damageAttr.min) {
      avg = damageAttr.min
    }

    // 看是否为主流派 主流派的话平均 = （本流派属性 + 世界等级 + 武学等级 + 1） * 1.5
    if (main) {
      const add_avg = this.world_level + this.skill_level + 1
      avg = this.calc.mul(this.calc.add(avg, add_avg), 1.5)
    }

    // 穿透计算 固定伤害 外功伤害吃通用的穿透 其他属性的吃属性穿透
    const desc = this.calc.desc(damageAttr.chuanTou, this.Attr.TongYong.diKang)
    let chuanTou = 0
    if (desc > 0) {
      chuanTou = this.calc.div(desc, 2)
    } else {
      chuanTou = desc
    }
    const chuanTouRate = this.calc.add(1, this.calc.div(chuanTou, 100))

    // 计算会心 * 技能倍率 * attr中的穿透 * attr中的增伤
    let huiXinLast = this.calc.mul(
      this.calc.mul(avg, rate.huiXin),
      this.calc.add(1, this.Attr.TongYong.huiXinAdd),
    )
    huiXinLast = this.calc.mul(huiXinLast, skill.rate)
    huiXinLast = this.calc.mul(huiXinLast, chuanTouRate)
    huiXinLast = this.calc.mul(huiXinLast, this.calc.add(1, damageAttr.add))

    // 会意 * 技能倍率 * attr中的穿透 * attr中的增伤
    let huiYiLast = this.calc.mul(
      this.calc.mul(damageAttr.max, rate.huiYi),
      this.calc.add(1, this.Attr.TongYong.huiYiAdd),
    )
    huiYiLast = this.calc.mul(huiYiLast, skill.rate)
    huiYiLast = this.calc.mul(huiYiLast, chuanTouRate)
    huiYiLast = this.calc.mul(huiYiLast, this.calc.add(1, damageAttr.add))

    // 擦伤 * 技能倍率 * attr中的穿透 * attr中的增伤
    let caShangLast = this.calc.mul(
      this.calc.mul(damageAttr.min, rate.caShang),
      this.calc.add(1, this.Attr.CaShang.add),
    )
    caShangLast = this.calc.mul(caShangLast, skill.rate)
    caShangLast = this.calc.mul(caShangLast, chuanTouRate)
    caShangLast = this.calc.mul(caShangLast, this.calc.add(1, damageAttr.add))

    // 普通伤害 * 技能倍率 * attr中的穿透 * attr中的增伤
    let noramlLast = this.calc.mul(avg, rate.normal)
    noramlLast = this.calc.mul(noramlLast, skill.rate)
    noramlLast = this.calc.mul(noramlLast, chuanTouRate)
    noramlLast = this.calc.mul(noramlLast, this.calc.add(1, damageAttr.add))

    const last = this.calc.add(
      this.calc.add(this.calc.add(huiXinLast, huiYiLast), caShangLast),
      noramlLast,
    )

    return {
      last: last,
      huiYi: huiYiLast,
      huiXin: huiXinLast,
      caShang: caShangLast,
      noraml: noramlLast,
    }
  }
}

export default Damage
